function [theta_hat, Sigma_theta_hat] = GMM_Estimator(data,theta0,giveMoments,giveWeight,giveVarianceEstim)
%Calculates GMM estimator and estimated variance matrix based on moments
%specifide by giveMoments, weighting matrix specified by giveWeight, where
%theta0 gives the staring value for GMM estimation and giveVarinceEstim
%specifies the estimator used to compute the variance matrix

moments=str2func(giveMoments);
VarianceEstimator=str2func(giveVarianceEstim);
W_func=str2func(giveWeight);


g=@(theta) mean(moments(data,theta,0))';
W=@(theta) W_func(data,theta);
obj=@(theta) g(theta)'*W(theta)*g(theta);
options=optimset('MaxIter',10^4,'MaxFunEvals',10^4);
theta_hat=fminsearch(obj,theta0,options);

q_array=moments(data,theta_hat,1);
for n=1:size(q_array,3)
    G(:,n)=mean(q_array(:,:,n))';
end

Sigma_hat=VarianceEstimator(moments(data,theta_hat,0));
W_hat=W(theta_hat);
Sigma_theta_hat=(G'*W_hat*G)^-1*G'*W_hat*Sigma_hat*W_hat*G*(G'*W_hat*G)^-1;
end

